﻿using System.Collections.Generic;
using System.Diagnostics;
using LFSRecord2.Model.UserActions;
using System.Collections.ObjectModel;

namespace LFSRecord2.Model.Undo
{
    public class UndoManager
    {
        //private ProjectData _initialState;

        private int _currentIndex = -1;
        private List<UndoLevel> _levels = new List<UndoLevel>();

        private UndoLevel _currentActions = new UndoLevel();

        public UndoManager()
        {
        }

        /// <summary>
        /// Reset the undo manager, which means delete all undo data and create a new initial state
        /// </summary>
        public void Reset()
        {
            _currentIndex = -1;
            _levels.Clear();
            _currentActions = new UndoLevel();
            //_initialState = LFSRecordController.project.DataStructure();
        }

        /// <summary>
        /// Add a user action to our temporary undo level's action collection. When you CommitUserActions() you commit these added actions to a new undo level.
        /// </summary>
        /// <param name="action">The object describing the user action</param>
        public void AddUserAction(UserActionBase action)
        {
            _currentActions.Actions.Add(action);
        }

        /// <summary>
        /// Prepend a user action to our temporary undo level's action collection. Use with care.
        /// </summary>
        /// <param name="action">The object describing the user action</param>
        public void PrependUserAction(UserActionBase action)
        {
            _currentActions.Actions.Insert(0, action);
        }

        /// <summary>
        /// Commit the accumulated user actions into a new undo level.
        /// </summary>
        public void CommitUserActions()
        {
            if (_currentActions.Actions.Count == 0)
                return;

            if (_currentIndex != _levels.Count - 1)
            {
                //Debug.WriteLine("Undo levels : Cleanup range from index {0}, {1} items", _currentIndex + 1, _levels.Count - (_currentIndex + 1));
                // We have to do some cleaning of appended levels that we'll no longer need
                _levels.RemoveRange(_currentIndex + 1, _levels.Count - (_currentIndex + 1));
            }

            Debug.WriteLine("Adding a new undo level ({0}) with {1} user actions", _currentIndex + 1, _currentActions.Actions.Count);

            _levels.Add(_currentActions);
            _currentActions = new UndoLevel(); 
            _currentIndex++;
        }

        public bool CanUndo()
        {
            return (_currentIndex > -1);
        }

        public bool CanRedo()
        {
            return (_currentIndex + 1 < _levels.Count);
        }

        public bool DoUndo(LfsRecordProject project)
        {
            if (!CanUndo())
                return false;

            // Set all layer UpdatedCurrentValues to 0
            LfsRecordController.project.UpdatedCurrentValuesToZero();

            for (int i = _levels[_currentIndex].Actions.Count - 1; i >= 0; i--)
            {
                _levels[_currentIndex].Actions[i].DoUndo();
            }

            _currentIndex--;

             LfsRecordController.project.LayerPostProcess();
            
            return true;
        }

        public bool DoRedo(LfsRecordProject project)
        {
            if (!CanRedo())
                return false;

            // Set all layer UpdatedCurrentValues to 0
            LfsRecordController.project.UpdatedCurrentValuesToZero();

            _currentIndex++;

            foreach (UserActionBase action in _levels[_currentIndex].Actions)
            {
                action.DoRedo();
            }

            LfsRecordController.project.LayerPostProcess();

            return true;
        }
    }
}
